#include "expcomparer.h"
#include "ui_expcomparer.h"
#include "peexportlist.h"

#include <QMessageBox>
#include <QListWidget>
#include <QListWidgetItem>
#include <QFileDialog>
#include <QString>
#include <QFile>
#include <QCryptographicHash>

#include <windows.h>
#include <imagehlp.h>



ExpComparer::ExpComparer(QWidget *parent)
    : QDialog(parent), ui(new Ui::ExpComparer)
{
    ui->setupUi(this);
}

ExpComparer::~ExpComparer()
{
    delete ui;
}

void ExpComparer::on_pushButton_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Choise First DLL"), "C:/", tr("Image Files (*.dll)"));
    ui->lineEdit->setText(fileName);
}

void ExpComparer::on_pushButton_2_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("Choise Second DLL"), "C:/", tr("Image Files (*.dll)"));
    ui->lineEdit_2->setText(fileName);
}

void ExpComparer::FillDetails(char * pszFilename1, char * pszFilename2)
{
    LOADED_IMAGE li;
    LOADED_IMAGE li2;

    if ( !MapAndLoad( pszFilename1, "", &li, TRUE, TRUE ) )
    {
        printf( "Unable to locate or load %s\n", pszFilename1 );
        return;
    }

    QString moduleName = QString(li.ModuleName);
    ui->lineEdit_3->setText(moduleName);
    moduleName = moduleName.setNum(li.Characteristics,16);
    ui->lineEdit_4->setText(moduleName);
    moduleName = moduleName.setNum(li.NumberOfSections,10);
    ui->lineEdit_5->setText(moduleName);
    moduleName = moduleName.setNum(li.SizeOfImage,16);
    ui->lineEdit_7->setText(moduleName);

    QFile file(ui->lineEdit->text());

    if(!file.open(QIODevice::ReadOnly))
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText("Unable to Open "+ui->lineEdit->text());
        msgBox.exec();
    }

    else
    {
        QByteArray content = file.readAll();
        moduleName = QCryptographicHash::hash(content,QCryptographicHash::Md5).toHex();
        ui->lineEdit_6->setText(moduleName);
        file.close();
    }


    if ( !MapAndLoad( pszFilename2, "", &li2, TRUE, TRUE ) )
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText("Unable to locate or load file");
        msgBox.exec();
        return;
    }

    moduleName = QString(li2.ModuleName);
    ui->lineEdit_8->setText(moduleName);
    moduleName = moduleName.setNum(li2.Characteristics,16);
    ui->lineEdit_9->setText(moduleName);
    moduleName = moduleName.setNum(li2.NumberOfSections,10);
    ui->lineEdit_10->setText(moduleName);
    moduleName = moduleName.setNum(li2.SizeOfImage,16);
    ui->lineEdit_12->setText(moduleName);

    QFile file1(ui->lineEdit_2->text());

    if(!file1.open(QIODevice::ReadOnly))
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText("Unable to Open "+ui->lineEdit_2->text());
        msgBox.exec();
    }

    else
    {
        QByteArray content = file1.readAll();
        moduleName = QCryptographicHash::hash(content,QCryptographicHash::Md5).toHex();
        ui->lineEdit_11->setText(moduleName);
        file1.close();
    }

    return;
}


BOOL ExpComparer::LoadExportInfo( char * pszFilename, PEExportList * pExportList )
{
    LOADED_IMAGE li;

    if ( !MapAndLoad( pszFilename, "", &li, TRUE, TRUE ) )
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText( "Unable to locate or load file");
        msgBox.exec();
        return FALSE;
    }

    PIMAGE_EXPORT_DIRECTORY pExpDir;
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)(li.FileHeader->OptionalHeader.
                                        DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    if ( !pExpDir )
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText("No Exports");
        msgBox.exec();
        return FALSE;
    }
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)ImageRvaToVa(
            li.FileHeader, li.MappedAddress, (DWORD)pExpDir, 0 );
    PDWORD* pExpNames =(LPDWORD*) pExpDir->AddressOfNames;
    pExpNames = (PDWORD *)ImageRvaToVa(
            li.FileHeader, li.MappedAddress, (DWORD)pExpNames, 0 );
    for ( unsigned i=0; i < pExpDir->NumberOfNames; i++ )
    {
        PSTR p = (PSTR)ImageRvaToVa(
                li.FileHeader, li.MappedAddress, (DWORD)*pExpNames, 0 );
        pExportList->AddSymbol( p );
        pExpNames++;

    }

    if ( pExpDir->NumberOfNames < pExpDir->NumberOfFunctions )
    {        
        PWORD pNameOrdinals = (PWORD)ImageRvaToVa(
                li.FileHeader, li.MappedAddress,
                (DWORD)pExpDir->AddressOfNameOrdinals, 0 );
        PDWORD pFunctions = (PDWORD)ImageRvaToVa(
                li.FileHeader, li.MappedAddress,
                (DWORD)pExpDir->AddressOfFunctions, 0 );
        DWORD cNamedOrdinals = pExpDir->NumberOfNames;
        DWORD cFunctions = pExpDir->NumberOfFunctions;
        PBYTE pNamedFuncs = (PBYTE)calloc( cFunctions, sizeof(BYTE) );
        PWORD pCurrOrd = pNameOrdinals;

        for ( int i = 0; i < cNamedOrdinals; i++, pCurrOrd++ )
            pNamedFuncs[ *pCurrOrd ] = 1;

        for ( int i = 0; i < cFunctions; i++ )
        {
            if ( pNamedFuncs[i] )
                continue;
            if ( 0 == pFunctions[i] )
                continue;
            char szMadeUpName[64];
            sprintf(szMadeUpName,"ordinal_%u",(const char*) pExpDir->Base + i );
            pExportList->AddSymbol( szMadeUpName );
        }
        free( pNamedFuncs );
    }
    UnMapAndLoad( &li );
    return TRUE;
}

void ExpComparer::on_pushButton_3_clicked()
{
    if ( ( ui->lineEdit->text().length() == 0) || ( ui->lineEdit_2->text().length() == 0))
    {
        QMessageBox msgBox;
        msgBox.adjustSize();
        msgBox.setText("Both path fields need to be filled");
        msgBox.exec();
        return;
    }

    else
    {
        char* pszFile1 = 0;
        char* pszFile2 = 0;
        QString pathConversion= ui->lineEdit->text();
        QString pathConversion_1= ui->lineEdit_2->text();
        QByteArray pathC = pathConversion.toAscii();
        QByteArray pathC_1 = pathConversion_1.toAscii();

        pszFile1 = pathC.data();
        pszFile2 = pathC_1.data();

        PEExportList file1;
        if ( !LoadExportInfo( pszFile1, &file1 ) )
            return;

        PEExportList file2;
        if ( !LoadExportInfo( pszFile2, &file2 ) )
            return;
        ExportedSymbolInfo * pCurrent = 0;

        while ( pCurrent = file1.GetNextSymbol(pCurrent) )
        {
            ExportedSymbolInfo * pMatch = file2.LookupSymbol( pCurrent->m_pszName );
            if ( pMatch )
            {
                pCurrent->m_flags |= EXPSYMINFO_MATCH;
                pMatch->m_flags   |= EXPSYMINFO_MATCH;
            }
        }

        int row = 0;

        if ((ui->listWidget->count()) != 0)
        {
            ui->listWidget->clear();
            ui->listWidget_2->clear();
            ui->listWidget_3->clear();
        }

        while ( pCurrent = file1.GetNextSymbol(pCurrent) )
        {
           if ( 0 == pCurrent->m_flags & EXPSYMINFO_MATCH )
            {
                QString exportName = QString(pCurrent->m_pszName);               
                QListWidgetItem *newItem = new QListWidgetItem;
                QListWidgetItem *newItem1 = new QListWidgetItem;
                newItem->setText(exportName);
                newItem1->setText(exportName);
                ui->listWidget->insertItem(row,newItem);
                ui->listWidget_3->insertItem(row,newItem1);
                row++;
            }
        }

        pCurrent = 0;
        row = 0;

        while ( pCurrent = file2.GetNextSymbol(pCurrent) )
        {
            if ( 0 == pCurrent->m_flags & EXPSYMINFO_MATCH )
            {
                QString exportName = QString(pCurrent->m_pszName);
                QListWidgetItem *newItem = new QListWidgetItem;
                QListWidgetItem *newItem1 = new QListWidgetItem;
                newItem->setText(exportName);
                newItem1->setText(exportName);
                ui->listWidget_2->insertItem(row,newItem);
                ui->listWidget_3->insertItem(row + ui->listWidget_3->count(),newItem1);
                row++;
            }
        }
        ExpComparer::FillDetails(pszFile1, pszFile2);
        if ( (QString::compare(ui->lineEdit_6->text(),ui->lineEdit_11->text())) != 0)
            ui->label_14->setText("Hash Check: DLL Differs");
        else
            ui->label_14->setText("Hash Check: DLL are Equal");
    }
}

void ExpComparer::on_pushButton_6_clicked()
{
    ExpComparer::close();
}

void ExpComparer::on_pushButton_4_clicked() // Logger
{
    QFile file("Diff");
    file.open(QIODevice::WriteOnly);
    file.write("######################\n");
    file.write("DLL Export Differentiation \n");
    file.write("######################\n");
    file.write("#First DLL Export: \n");

    for (int i = 0; i< ui->listWidget->count(); i++)
        file.write(ui->listWidget->item(i)->text().toUtf8() + "\n");

    file.write("#Second DLL Export: \n");

    for (int i = 0; i< ui->listWidget_2->count(); i++)
        file.write(ui->listWidget_2->item(i)->text().toUtf8() + "\n");

    file.write("#Common: \n");

    for (int i = 0; i< ui->listWidget_2->count(); i++)
        file.write(ui->listWidget_3->item(i)->text().toUtf8() + "\n");

    file.close();

}

void ExpComparer::on_pushButton_5_clicked()
{
    QMessageBox msgBox;
    msgBox.adjustSize();
    msgBox.setText("Dll Export Comparer 1.0 has been coded by Giuseppe 'Evilcry' Bonfa' \n http://evilcry.netsons.org ~ http://evilcodecave.blogspot.com");
    msgBox.exec();

}
